
let JsonConfigFile = require("../../../utils/JsonConfigFile");
const Response = require("../../class/Response");
const LocalEvent = require("../../class/LocalEvent");

// [意外退出恢复] WSS服务端启动后检查意外退出状态
let waitFixSubBds = {};
let waitFixNum = 0;
WSS.on('serverstart', ()=>{
    let allPlayersSyncTemp = CONF.PLAYERSYNCTEMP.readAllParse();
    for (let key in allPlayersSyncTemp){
        let plTemp = allPlayersSyncTemp[key];
        if (plTemp['lastLogoutSuccess'] == false){
            if(waitFixNum == 0){
                WSS.logger.warn('========== 检查到玩家意外退出未同步状态 ==========');
            }
            let bdsUuid = plTemp.lastLogoutBDSuuid;
            let bdsName = plTemp.lastLogoutBDSname;
            let {xuid, uuid, realName} = plTemp;
            // 新建副服记录
            if (!waitFixSubBds[bdsUuid]){
                waitFixSubBds[bdsUuid] = {
                    bdsUuid: bdsUuid,
                    bdsName: bdsName,
                    faildPlayersInfo: {},
                };
            }
            // 添加玩家
            waitFixSubBds[bdsUuid].faildPlayersInfo[uuid] = {
                xuid: xuid,
                uuid: uuid,
                realName: realName,
            };
            waitFixNum++;
        }
    }
    if (waitFixNum != 0){
        WSS.logger.warn(`总计: ${waitFixNum} 名玩家未同步 | 待副服连接后将恢复同步`);
        WSS.logger.warn(`暂时无法同步的玩家: ${Object.values(waitFixSubBds)
            .flatMap(bdsInfo => Object.values(bdsInfo.faildPlayersInfo))
            .map(playerInfo => playerInfo.realName)
            .join(', ')}`
        );
        WSS.logger.warn(`无法同步涉及的BDS: ${Object.values(waitFixSubBds)
            .map(bdsInfo => bdsInfo.bdsName)
            .join(', ')}`
        );
    }
});

// [意外退出恢复] 监听BDS成功注册到WS协调服务端后，发送强制同步命令
WSS.api.listener.on(CONSTANTS.EVENT.CLIENT_CONNECT, (json)=>{
    let bdsInfo = json.body.data;
    if (bdsInfo.userType != 'bds'){return;}
    if (!waitFixSubBds[bdsInfo.bds.uuid]){return;}
    let waitFixNumStart = waitFixNum;
    for (let playerInfo of Object.values(waitFixSubBds[bdsInfo.bds.uuid].faildPlayersInfo)){
        WSS.clientsManager.getClientByBDSuuid(bdsInfo.bds.uuid).sendJson(new Response()
            .setUrl('/bds/sync/syncPlayerData/checkAndForceSync')
            .setData({
                ...playerInfo,
                lastLogoutSuccess: true // 传递到WS服务端 /bds/sync/syncPlayerData 以恢复同步
            }),
            (req, res)=>{
                if (req.body.statusCode == 0){
                    waitFixNum--;
                    WSS.logger.warn(`[意外退出恢复] ${playerInfo.realName} 已恢复同步 | BDS: ${bdsInfo.name} | 剩余未恢复同步玩家数量: ${waitFixNum}`); 
                    delete waitFixSubBds[bdsInfo.bds.uuid].faildPlayersInfo[playerInfo.uuid];
                }else{
                    WSS.logger.error(`[意外退出恢复] ${playerInfo.realName} 恢复同步失败: ${req.body.statusMessage}`);
                }
            }
        );
    }
});

// ==========================================
// 登录同步 请求登录环境
WSS.get('/bds/sync/loginSync/getEnvironmentInfo', async (thisClient, req, res)=>{
    if (req.body.statusCode != 0){return false;}
    thisClient.sendJson(Response.replyTo(req)
        .setUrl('/bds/sync/loginSync/getEnvironmentInfo/result')
        .setData({
            // 玩家同步缓存，记录了意外退出状态
            playerSyncTemp: CONF.PLAYERSYNCTEMP.get(req.body.data.uuid),
            // 当前在线连接，判断主服是否在线
            onlineClientsInfo: WSS.clientsManager.getOnlineClientsInfo(),
            xuid: req.body.data.xuid,
            uuid: req.body.data.uuid,
            realName: req.body.data.realName
        })
    );
    return false;
});

// 登录同步 请求玩家数据
WSS.get('/bds/sync/loginSync/getPlayerData', async (thisClient, req, res)=>{
    if (req.body.statusCode != 0){return false;}
    let res_ori = Response.replyTo(req)
        .setUrl('/bds/sync/loginSync/getPlayerData/result');
    let clientMainBDS = WSS.clientsManager.getClientMainBDS();
    if (clientMainBDS == null){
        thisClient.sendJson(
            res_ori.setStatusCode(1)
            .setStatusMessage('请求玩家数据失败, 未找到BDS主服')
            .setData({
                playerSyncTemp: req.body.data.playerSyncTemp,
                onlineClientsInfo: req.body.data.onlineClientsInfo,
                xuid: req.body.data.xuid,
                uuid: req.body.data.uuid,
                realName: req.body.data.realName
            })
        );
        WSS.logger.error('请求玩家数据失败, 未找到BDS主服');
        return false;
    }

    clientMainBDS.sendJson(Response.fromRequest(req)
        .setUrl('/bds/sync/loginSync/getPlayerData/requestMainBDS')
        .setData({
            playerSyncTemp: req.body.data.playerSyncTemp,
            onlineClientsInfo: req.body.data.onlineClientsInfo,
            xuid: req.body.data.xuid,
            uuid: req.body.data.uuid,
            realName: req.body.data.realName
        }),
        (req, res) => {
            if (req.body.statusCode != 0){
                res_ori.setStatusCode(1)
                    .setStatusMessage(req.body.statusMessage)
                    .setData(req.body.data);
                WSS.logger.warn('请求玩家数据失败, 主服无此玩家数据 ' + req.body.data.realName);
            }else{
                res_ori.setStatusCode(0)
                    .setStatusMessage(req.body.statusMessage)
                    .setData({
                        playerData: req.body.data.playerData,
                        playerSyncTemp: req.body.data.playerSyncTemp,
                        onlineClientsInfo: req.body.data.onlineClientsInfo,
                        xuid: req.body.data.xuid,
                        uuid: req.body.data.uuid,
                        realName: req.body.data.realName
                    });
            }
            let clientOri = WSS.clientsManager.getClientByBDSuuid(res_ori.header.source_bds_uuid);
            if (clientOri == null){
                WSS.logger.error('响应玩家数据失败, 发起请求的BDS已下线');
                return false;
            }
            clientOri.sendJson(res_ori.json);
            return false;
        }
    );
    return false;
});

// 登录同步完成 更新玩家同步缓存状态
WSS.get('/bds/sync/loginSync/result', async (thisClient, req, res)=>{
    let playerInfo = req.body.data;
    if (req.body.statusCode == 0){
        // 更新同步缓存状态(主服玩家上次退出状态始终为true, 即永远不置为意外退出状态)
        let plSyncTemp = CONF.PLAYERSYNCTEMP.get(playerInfo.uuid);
        if (plSyncTemp == null){
            CONF.PLAYERSYNCTEMP.set(playerInfo.uuid, {
                uuid: playerInfo.uuid,
                xuid: playerInfo.xuid,
                realName: playerInfo.realName,
                lastLogoutSuccess: thisClient.bds.syncType == 'main' ? true : false,
                lastLogoutBDSuuid: thisClient?.bds?.uuid,
                lastLogoutBDSname: thisClient.name,
                lastLogoutTime: 0,
                lastSyncTime: new Date().getTime()
            });
        }else{
            plSyncTemp.realName = playerInfo.realName;
            if (thisClient.bds.syncType == 'main'){
                plSyncTemp.lastLogoutSuccess = true;
            }else{
                plSyncTemp.lastLogoutSuccess = false;
            }
            plSyncTemp.lastLogoutBDSuuid = thisClient?.bds?.uuid;
            plSyncTemp.lastLogoutBDSname = thisClient.name;
            plSyncTemp.lastSyncTime = new Date().getTime();
            CONF.PLAYERSYNCTEMP.set(playerInfo.uuid, plSyncTemp);
        }

        WSS.clientsManager.broadcastJson(new Response()
            .setUrl(CONSTANTS.EVENT.PLAYER_LOGIN_SYNC_SUCCESS)
            .setSourceId(thisClient.id)
            .setSourceBdsUuid(thisClient.bds.uuid)
            .setSourceBdsServerName(thisClient.name)
            .setData({
                xuid: playerInfo.xuid,
                uuid: playerInfo.uuid,
                realName: playerInfo.realName
            })
        );

        // 本地事件
        WSS.api.listener.emit(CONSTANTS.EVENT.PLAYER_LOGIN_SYNC_SUCCESS, new LocalEvent()
            .setSourceId(thisClient.id)
            .setSourceBdsUuid(thisClient.bds.uuid)
            .setSourceBdsServerName(thisClient.name)
            .setStatusCode(0)
            .setStatusMessage(``)
            .setData({
                xuid: playerInfo.xuid,
                uuid: playerInfo.uuid,
                realName: playerInfo.realName
            }).json
        );
        return false;
    }
});

// 玩家正常退出同步，更新玩家同步缓存状态
WSS.get('/bds/sync/playerLogout', async (thisClient, req, res)=>{
    let playerInfo = req.body.data;
    let plSyncTemp = CONF.PLAYERSYNCTEMP.get(playerInfo.uuid);
    if (plSyncTemp == null){
        //WSS.logger.error('意外错误, 登出时玩家同步缓存为空(应该在登录时记录玩家同步缓存)');
        return false;
    }
    plSyncTemp.lastLogoutSuccess = true;
    plSyncTemp.lastLogoutBDSuuid = thisClient?.bds?.uuid;
    plSyncTemp.lastLogoutBDSname = thisClient.name;
    plSyncTemp.lastLogoutTime = new Date().getTime();
    CONF.PLAYERSYNCTEMP.set(playerInfo.uuid, plSyncTemp);
});


// ==========================================
// 日常同步请求
WSS.get('/bds/sync/syncPlayerData', async (thisClient, req, res)=>{
    if (req.body.statusCode != 0){return false;}
    let res_ori = Response.replyTo(req)
        .setUrl('/bds/sync/syncPlayerData/result');

    let clientMainBDS = WSS.clientsManager.getClientMainBDS();
    if (clientMainBDS == null){
        thisClient.sendJson(
            res_ori.setStatusCode(1)
                .setStatusMessage('请求同步玩家数据失败, 未找到BDS主服')
                .setData(req.body.data)
        );
        WSS.logger.error('请求同步玩家数据失败, 未找到BDS主服');
        return false;
    }

    // 请求主服同步数据
    clientMainBDS.sendJson(Response.fromRequest(req)
        .setUrl('/bds/sync/syncPlayerData/requestMainBDS')
        .setData({
            ...req.body.data,
            playerData: req.body.data.playerData,
            xuid: req.body.data.xuid,
            uuid: req.body.data.uuid,
            realName: req.body.data.realName
        }),
        (req, res) => {
            // 主服同步数据失败
            if (req.body.statusCode != 0){
                res_ori.setStatusCode(1)
                    .setStatusMessage('请求同步玩家数据失败, 主服保存数据失败')
                    .setData({
                        ...req.body.data,
                        xuid: req.body.data.xuid,
                        uuid: req.body.data.uuid,
                        realName: req.body.data.realName
                    });
                WSS.logger.error('请求同步玩家数据失败, 主服保存数据失败');
            }
            // 主服同步数据成功
            else{
                res_ori.setStatusCode(0)
                    .setStatusMessage('请求同步玩家数据成功')
                    .setData({
                        ...req.body.data,
                        xuid: req.body.data.xuid,
                        uuid: req.body.data.uuid,
                        realName: req.body.data.realName
                    });

                // 更新上次同步时间
                CONF.PLAYERSYNCTEMP.set(
                    req.body.data.uuid, 
                    {
                        ...CONF.PLAYERSYNCTEMP.get(req.body.data.uuid), 
                        lastSyncTime: new Date().getTime()
                    }
                );

                // 修复意外退出同步
                if (req.body.data.lastLogoutSuccess != undefined){
                    CONF.PLAYERSYNCTEMP.set(
                        req.body.data.uuid, 
                        {
                            ...CONF.PLAYERSYNCTEMP.get(req.body.data.uuid), 
                            lastLogoutSuccess: req.body.data.lastLogoutSuccess,
                            lastSyncTime: new Date().getTime()
                        }
                    );
                }
            }

            let clientOri = WSS.clientsManager.getClientByBDSuuid(res_ori.header.source_bds_uuid);
            if (clientOri == null){
                WSS.logger.error(`[syncPlayerData] 响应同步玩家数据失败, 发起请求的BDS(${res_ori.header.source_bds_name})已下线`);
                return false;
            }
            clientOri.sendJson(res_ori.json);
            return false;
        }
    );
    return false;
});


// ==========================================
// LLMoney同步
WSS.get('/bds/sync/syncllmoney', async (thisClient, req, res)=>{
    res.header.url = '/bds/sync/setllmoney';
    res.body.data = {
        xuid: req.data.xuid,
        value: req.data.value
    };
    // 将llmoney set信息广播到所有服务器
    WSS.clientsManager.broadcastJson(res.json, [thisClient.id]);
    return false;
});

WSS.get('/bds/sync/getAllPlayersLLMoney', async (thisClient, req, res)=>{
    if (req.body.statusCode != 0){return false;}
    let res_ori = Response.replyTo(req)
        .setUrl('/bds/sync/getAllPlayersLLMoney/result');

    let clientMainBDS = WSS.clientsManager.getClientMainBDS();
    if (clientMainBDS == null){
        thisClient.sendJson(res_ori.setStatusCode(1)
            .setStatusMessage('请求所有玩家最新llmoney数据失败, 未找到BDS主服, 主服连接后会重新获取')
            .setData(req.body.data)
        );
        WSS.logger.warn('请求所有玩家最新llmoney数据失败, 未找到BDS主服, 主服连接后会重新获取');
        return false;
    }
    
    // 请求主服获取所有玩家LLMoney数据
    clientMainBDS.sendJson(Response.fromRequest(req)
        .setUrl('/bds/sync/getAllPlayersLLMoney/requestMainBDS')
        .setData({
            xuids: Object.values(CONF.PLAYERSYNCTEMP.readAllParse()).map(plSyncTemp=>plSyncTemp.xuid)
        }),
        (req, res)=>{
            if (req.body.statusCode != 0){
                res_ori.setStatusCode(1)
                    .setStatusMessage('请求所有玩家LLMoney数据失败, 主服获取数据失败')
                    .setData(req.body.data);
                WSS.logger.error('请求所有玩家LLMoney数据失败, 主服获取数据失败');
            }else{
                res_ori.setStatusCode(0)
                    .setStatusMessage('请求所有玩家LLMoney数据成功')
                    .setData({
                        allLLMoney: req.body.data.allLLMoney
                    });
            }
            let clientOri = WSS.clientsManager.getClientByBDSuuid(res_ori.header.source_bds_uuid);
            if (clientOri == null){
                WSS.logger.error('响应所有玩家LLMoney数据失败, 发起请求的BDS已下线');
                return false;
            }
            clientOri.sendJson(res_ori.json);
            return false;
        }
    );
    return false;
});


// ==========================================
// 控制台命令同步
WSS.get('/bds/sync/syncCmd', async (thisClient, req, res)=>{
    res.header.url = '/bds/sync/executeCmd';
    res.body.data = {
        commandLine: req.data.commandLine
    };
    WSS.clientsManager.broadcastJson(res.json, [thisClient.id]);
});

// module.exports = {
//     checkLogoutSyncSuccess
// };
